package com.koron.common.core.filter;

import cn.hutool.core.util.StrUtil;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

public class RequestWrapper extends HttpServletRequestWrapper {

    private byte[] body = new byte[]{};

    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        if ((HttpMethod.POST.matches(request.getMethod()) || HttpMethod.PUT.matches(request.getMethod()))) {

            String value = request.getContentType();
            //付工报表来的 特殊处理一下
            if ("content=text/html;charset=ANSI".equals(value)) {
                value = MediaType.TEXT_HTML_VALUE;
            }
            MediaType contentType = StringUtils.hasLength(value) ? MediaType.parseMediaType(value) : null;
            if (shouldRecordBody(contentType)){
                body = readBytes(request.getReader(), "utf-8");
            }
        }
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream(), "utf-8"));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener listener) {
            }

            @Override
            public int read() throws IOException {
                return bais.read();
            }
        };
    }

    /**
     * 通过BufferedReader和字符编码集转换成byte数组
     *
     * @param br
     * @param encoding
     * @return
     * @throws IOException
     */
    private byte[] readBytes(BufferedReader br, String encoding) throws IOException {
        String str = null;
        StringBuilder sb = new StringBuilder();
        while ((str = br.readLine()) != null) {
            sb.append(str);
        }
        String handleStr = handeleRequestStr(sb);//处理不间断空格

        return handleStr.getBytes(Charset.forName(encoding));
    }

    /**
     * 处理不间断空格
     * @param sb
     * @return
     */
    private String handeleRequestStr(StringBuilder sb) {
        String handleStr = StrUtil.replace(sb.toString(), "\u00A0", "\u0020");
        return handleStr;
    }

    private boolean shouldRecordBody(MediaType contentType) {
        if (contentType == null) {
            return true;
        }
        String type = contentType.getType();
        String subType = contentType.getSubtype();

        if ("application".equals(type)) {
            return "json".equals(subType) || "x-www-form-urlencoded".equals(subType) || "xml".equals(subType) || "atom+xml".equals(subType) || "rss+xml".equals(subType);
        } else if ("text".equals(type)) {
            return true;
        }

        //暂时不记录form
        return false;
    }

}
